#!/usr/bin/env bash

## common part of requirements_rvm_pkg_* extracted from scripts/functions/requirements/rvm_pkg ->
requirements_rvm_pkg_config()
{
  PKG_CONFIG_PATH="${rvm_usr_path:-${rvm_path}/usr}/lib/pkgconfig:${rvm_usr_path:-${rvm_path}/usr}/lib64/pkgconfig:/opt:/usr:/usr/local" pkg-config "$@"
}

requirements_rvm_pkg_lib_installed()
{
  if is_a_function ${1}_installed && ${1}_installed
  then return 0
  fi
  requirements_rvm_pkg_config --list-all | __rvm_grep "^$1[- ]" >/dev/null || return $?
  true
}

requirements_rvm_pkg_libs_install()
{
  while
    (( $# ))
  do
    PKG_CONFIG_LIBDIR="${rvm_usr_path:-${rvm_path}/usr}/lib/pkgconfig" install_$1 || return $?
    shift
  done
}

requirements_rvm_pkg_after_uniqe_paths()
{
  \typeset __lib __lib_full_name
  for __lib
  do
    __lib_full_name=$( requirements_rvm_pkg_config --list-all | __rvm_awk "/^${__lib}[- ]/{print \$1}" )
    if
      [[ -n "${__lib_full_name}" ]]
    then
      requirements_rvm_pkg_config ${__lib_full_name} --variable=prefix
    elif
      [[ "${__lib}" == 'readline' ]]
    then
      # http://lists.gnu.org/archive/html/bug-readline/2010-09/msg00002.html
      echo ${rvm_usr_path:-${rvm_path}/usr}
    else
      rvm_error "Can not find ${__lib} in 'pkg-config'"
    fi
  done | sort -u
}

requirements_rvm_pkg_configure()
{
  \typeset -a __packages
  \typeset __package __target
  __target="$1"
  shift
  __rvm_read_lines __packages <(
    requirements_rvm_pkg_after_uniqe_paths "$@"
  )
  for __package in "${__packages[@]}"
  do __rvm_update_configure_opt_dir "$__target" "$__package"
  done
}
## common part of requirements_rvm_pkg_* extracted from scripts/functions/requirements/rvm_pkg <-

## helper for checking marking missing custom packages
requirements_rvm_pkg_lib_installed_custom()
{
  while
     (( $# ))
  do
    requirements_rvm_pkg_lib_installed "$1" || packages_custom+=( "$1" )
    shift
  done
}

## Real work for installing packages from source
install_package()
{
  __rvm_db "${package}_url" "package_url"
  __rvm_db "${package}_rename_dir" "package_rename_dir"
  (
    __rvm_cd "$rvm_src_path"
    __rvm_rm_rf "$rvm_src_path/$package-$version"
    local_file="$package-$version.$archive_format"
    rvm_log "Fetching $local_file to $rvm_archives_path"

    "$rvm_scripts_path/fetch" "$package_url/${remote_file:-$local_file}" "$local_file" || return $?
    __rvm_log_command "$package/extract" "Extracting ${package} to $rvm_src_path/$package-$version" \
      __rvm_package_extract "$rvm_archives_path/$local_file" "$rvm_src_path" ||
    case $? in
      199)
        rvm_error "\nUnrecognized archive format '$archive_format'"
        return 199
        ;;
      *)
        rvm_error "There has been an error while trying to extract the source. Halting the installation."
        return 1
        ;;
    esac

    if [[ -n "${package_rename_dir:-}" ]]
    then \command \mv "$rvm_src_path/${package_rename_dir}" "$rvm_src_path/$package-$version"
    fi
    __rvm_cd "$rvm_src_path/$package-$version"
    __rvm_add_to_path append /usr/bin

    if
      [[ -n "$patches" ]]
    then
      for patch in $(echo $patches | \command \tr ',' ' ')
      do
        __rvm_log_command "$package/patch" "Applying patch '$patch'..." __rvm_patch -p0 -f -i "$patch" ||
        {
          \typeset result=$?
          rvm_error "Patch $patch did not apply cleanly... back to the patching board :("
          exit $result
        }
      done
    fi

    if
      [[ "${rvm_skip_autoreconf_flag:-0}" == 0 ]] &&
      [[ -f configure.ac || -f configure.in ]]
    then
      if
        (( ${#rvm_autoconf_flags[@]} == 0 ))
      then
        case "${_system_type}" in
          (Windows) rvm_autoconf_flags=( -ivf )        ;; # no symlinks on windows :(
          (*)       rvm_autoconf_flags=( -is --force ) ;;
        esac
      fi
      __rvm_log_command "$package/autoreconf" "Prepare $package in $rvm_src_path/$package-$version." \
        __rvm_autoreconf "${rvm_autoconf_flags[@]}"
    fi

    [[ -n "${rvm_configure_env[*]}" ]] || rvm_configure_env=() # zsh can assume empty var => ( '' )
    (( ${#configure[@]} )) || configure=( ./configure )
    configure=(
      "${rvm_configure_env[@]}"
      "${configure[@]}" --prefix="${prefix_path:-$rvm_usr_path}"
      "${rvm_configure_flags[@]}" "${configure_flags[@]}"
    )

    __rvm_log_command "$package/configure" "Configuring $package in $rvm_src_path/$package-$version." \
      "${configure[@]}"

    unset configure_flags configure

    touch "$rvm_path/config/packages"
    if [[ "$action" == "uninstall" ]]
    then
      __rvm_log_command "$package/make.uninstall" "Uninstalling $package from ${prefix_path:-$rvm_usr_path}"  __rvm_make uninstall &&
      __rvm_cd "$rvm_src_path" &&
      __rvm_log_command "$package/rm_src.uninstall" "Removing ${package}-${version} from $rvm_src_path" \
        \command \rm -rf "$rvm_src_path/$package-$version" &&
      __rvm_db_ "$rvm_path/config/packages" "${package}" delete
    else
      __rvm_log_command "$package/make"         "Compiling $package in $rvm_src_path/$package-$version." \
        __rvm_make "${rvm_make_flags[@]}" &&
      __rvm_log_command "$package/make.install" "Installing $package to ${prefix_path:-$rvm_usr_path}" \
        __rvm_make install &&
      __rvm_db_ "$rvm_path/config/packages" "${package}" "${version}"
    fi
  )

  __function_on_stack __rvm_install_ruby ||
  rvm_warn "
Please note that it's required to reinstall all rubies:

    rvm reinstall all --force
"
}

package_installed()
{
  \typeset __search_path __lib_file __extension
  __search_path="${prefix_path:-${rvm_usr_path:-${rvm_path}/usr}}"

  [[ -f "${__search_path}/include/$1" ]] || return $?

  # __rvm_detect_system() does not support CYGWIN MINGW!
  case "${_system_type}" in
    (Darwin)  __extension="dylib" ;;
    (Windows) __extension="dll"   ;;
    (*)       __extension="so"    ;;
  esac
  __lib_file=$( __rvm_find "${__search_path}" -name "$2.${__extension}" | \command \head -n 1 )

  [[ -n "${__lib_file}" ]] || return $?

  case "${_system_type}" in
    (Darwin) lipo -info "${__lib_file}" | __rvm_grep "${_system_arch}" >/dev/null || return $? ;;
  esac
}

install_readline()
{
  package="readline" ; archive_format="tar.gz"
  __rvm_update_configure_opt_dir readline "${rvm_usr_path}"

  configure=( ./configure --disable-dependency-tracking )
  version="5.2"
  patches="$rvm_patches_path/$package-$version/shobj-conf.patch"
  install_package

  configure=( ./configure --disable-dependency-tracking )
  version="6.2"
  patches="$rvm_patches_path/$package-$version/patch-shobj-conf.diff"
  install_package
}
readline_installed()
{
  package_installed "readline/readline.h" "libreadline" || return $?
}

install_iconv()
{
  package="libiconv" ; version=1.13.1 ; archive_format="tar.gz"
  install_package
}

install_curl()
{
  package="curl" ; version=7.19.7 ; archive_format="tar.gz"
  install_package
}

install_openssl()
{
  \typeset -a openssl_use_asm
  package="openssl" ; archive_format="tar.gz"
  openssl_use_asm=( "no-asm" )
  __rvm_db "${package}_version" "version"
  if
    [[ "Darwin" == "${_system_type}" ]]
  then
    configure=( "./Configure" )
    if
      (( ${#rvm_architectures[@]} > 0 ))
    then
      if __rvm_string_match "${rvm_architectures[*]}" "64"
      then hw_cpu64bit=1
      fi
      if __rvm_string_match "${rvm_architectures[*]}" "ppc"
      then hw_machine="Power Macintosh"
      fi
    else
      hw_machine=$(sysctl hw.machine | __rvm_awk -F: '{print $2}' | __rvm_sed 's/^ //')
      hw_cpu64bit=$(sysctl hw.cpu64bit_capable | __rvm_awk '{print $2}')
    fi
    if
      [[ "Power Macintosh" == "$hw_machine" ]]
    then
      if [[ $hw_cpu64bit == 1 ]]
      then configure+=( "darwin64-ppc-cc" )
      else configure+=( "darwin-ppc-cc" )
      fi
    else
      if
       [[ $hw_cpu64bit == 1 ]]
      then
        configure+=( "darwin64-x86_64-cc" )
        openssl_use_asm=()
      else
        configure+=( "darwin-i386-cc" )
      fi
    fi
  else
    configure=( "./config" )
    if __rvm_compiler_version_or_higher "4.6"
    then openssl_use_asm=()
    fi
  fi
  configure+=( -I$rvm_usr_path/include -L$rvm_usr_path/lib zlib "${openssl_use_asm[@]}" no-krb5 )
  install_package
  __rvm_log_command openssl.certs "Updating openssl certificates" update_openssl_certs
}

update_openssl_certs()
(
  __rvm_cd "$rvm_usr_path/ssl" &&
  __rvm_curl https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt -o cert.pem ||
  __rvm_curl https://curl.haxx.se/ca/cacert.pem -o cert.pem
)
openssl_installed()
{
  package_installed "openssl/opensslv.h" "libssl" || return $?
}

install_zlib()
{
  package="zlib" ; version="1.2.7" ; archive_format="tar.gz"
  install_package
}

install_autoconf()
{
  package="autoconf" ; version="2.65" ; archive_format="tar.gz"
  prefix_path="$rvm_usr_path"
  install_package
}

install_ncurses()
{
  package="ncurses" ; version="5.7" ; archive_format="tar.gz"
  configure_flags=(
    --disable-rpath --without-debug --without-ada --enable-safe-sprintf --enable-sigwinch --without-progs
  )
  install_package
}

install_pkgconfig()
{
  package="pkg-config" ; version="0.23" archive_format="tar.gz"
  install_package
}

install_gettext()
{
  package="gettext" ; version="0.17" ; archive_format="tar.gz"
  install_package
}

install_libxml()
{
  install_libxml2 "$@"
}

install_libxml2()
{
  package="libxml2" ; version="2.7.3" ; archive_format="tar.gz"
  if
    [[ "Darwin" == "${_system_type}" ]]
  then
    configure=(
      ./configure --build=i686-apple-darwin$(command uname -r) --host=i686-apple-darwin$(command uname -r)
    )
  fi
  install_package
  unset prefix_path
}

install_libxslt()
{
  package="libxslt" ; version="1.1.26" ; archive_format="tar.gz"
  configure_flags=( --with-libxml-prefix="$rvm_usr_path" )
  if
    [[ "SunOS" == "${_system_type}" ]]
  then
    patches="$rvm_patches_path/$package-$version/solaris.patch"
  fi
  install_package
  unset prefix_path
}

install_yaml()
{
  install_libyaml "$@"
}

install_libyaml()
{
  package="yaml" ; archive_format="tar.gz"
  __rvm_db "${package}_version" "version"
  install_package
}

libyaml_installed()
{
  package_installed "yaml.h" "libyaml"
}

install_glib()
{
  ( install_pkgconfig; )
  ( install_gettext; )
  package="glib" ; version="2.23.1" ; archive_format="tar.gz"
  __rvm_update_configure_env CC="cc" \
    CFLAGS="-I${rvm_usr_path}/include" \
    LDFLAGS="-L${rvm_usr_path}/lib" \
    PKG_CONFIG="$rvm_usr_path/bin/pkg-config"
  install_package
}

install_mono()
{
  ( install_glib; )

  __rvm_mono_env
  package="mono" ; version="2.6.1" ; archive_format="tar.bz2"
  install_package
}

install_llvm()
{
  package="llvm"
  version="89156"
  (
    __rvm_cd $rvm_src_path
    if [[ ! -d "$rvm_src_path/llvm/.svn" ]] ; then
      __rvm_db "${package}_url" "package_url"
      __rvm_rm_rf "$rvm_src_path/llvm"
      svn co -r "$version" "$package_url" llvm
      __rvm_cd "$rvm_src_path/llvm"
      ./configure --enable-bindings=none
      UNIVERSAL=1 UNIVERSAL_ARCH="i386 x86_64" ENABLE_OPTIMIZED=1 __rvm_make -j2
      __rvm_try_sudo env UNIVERSAL=1 UNIVERSAL_ARCH="i386 x86_64" ENABLE_OPTIMIZED=1 __rvm_make install
    fi
  )
}

install_epel()
{
  mv="${_system_version%%.*}"
  if [[ "${_system_name}" == "CentOS" ]] && [[ -f /etc/yum.repos.d/epel.repo ]] ; then
    __rvm_db "epel${mv}_key" "epel_key"
    __rvm_db "epel${mv}_rpm" "epel_rpm"
    "${rvm_scripts_path}/fetch" "${epel_key}"
    "${rvm_scripts_path}/fetch" "${epel_rpm}"
    __rvm_try_sudo rpm --import "${rvm_archives_path}/${epel_key##*/}"
    __rvm_try_sudo rpm --quiet -i "${rvm_archives_path}/${epel_rpm##*/}"
  fi
}
